﻿using Framework.Common.Attributes;
using Framework.Common.Enums;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Framework.Common.DynamicInjection
{
    /// <summary>
    /// 动态注入
    /// </summary>
    public static class DynamicInjection
    {
        /// <summary>
        /// 根据attribute 自动注入
        /// </summary>
        /// <param name="services"></param>
        public static IServiceCollection AddAutoDIService(this IServiceCollection services)
        {
            var types = Directory.GetFiles(AppContext.BaseDirectory, "Goodwe.*.dll").Select(Assembly.LoadFrom).SelectMany(a => a.DefinedTypes)
                .Where(t => t.CustomAttributes.Any(q => q.AttributeType == typeof(InjectionAttribute))).ToList();

            foreach (var type in types)
            {
                InjectionAttribute? attri = (InjectionAttribute?)type.GetCustomAttribute(typeof(InjectionAttribute));
                if (attri == null) continue;
                if (type.IsClass)
                {
                    var interfaces = type.GetInterfaces();
                    if (interfaces.Length == 0)
                    {
                        if (attri.InjectionType == InjectionTypeEnum.Scoped)
                            services.AddScoped(type.UnderlyingSystemType);
                        else if (attri.InjectionType == InjectionTypeEnum.Transient)
                            services.AddTransient(type.UnderlyingSystemType);
                        else if (attri.InjectionType == InjectionTypeEnum.Singleton)
                            services.AddSingleton(type.UnderlyingSystemType);
                    }
                    else
                    {
                        foreach (var @interface in interfaces)
                        {
                            if (attri.InjectionType == InjectionTypeEnum.Scoped)
                                services.AddScoped(@interface, type.UnderlyingSystemType);
                            else if (attri.InjectionType == InjectionTypeEnum.Transient)
                                services.AddTransient(@interface, type.UnderlyingSystemType);
                            else if (attri.InjectionType == InjectionTypeEnum.Singleton)
                                services.AddSingleton(@interface, type.UnderlyingSystemType);
                        }
                    }
                }
            }

            return services;
        }
    }
}
